package com.block.source.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.block.common.constant.AppRspCodeConstant;
import com.block.common.enums.InfoTypeEnum;
import com.block.common.enums.ProfitSharingEnum;
import com.block.common.exception.NotifyExceptionService;
import com.block.common.model.dto.RequestTimeDTO;
import com.block.common.model.dto.SourceCountDTO;
import com.block.common.mq.MqSourceCountSendService;
import com.block.common.service.*;
import com.block.common.service.merchant.IMerchantThirdBaseInfoService;
import com.block.common.util.BigDecimalUtil;
import com.block.common.util.LocalDateUtil;
import com.block.common.vo.ResponseVo;
import com.block.datapush.enums.PushStatusEnum;
import com.block.datapush.factory.PushExtDataFactory;
import com.block.datapush.model.ProtocolInfoEntity;
import com.block.db.entity.*;
import com.block.db.mapper.MemberSourceInfoMapper;
import com.block.db.mapper.MerchantBaseInfoMapper;
import com.block.db.mapper.SourcePushResultInfoMapper;
import com.block.match.enums.OrderStatusEnum;
import com.block.match.model.dto.SourceMatchResultDTO;
import com.block.match.model.dto.SourceRegisterResultDTO;
import com.block.match.service.IDataMatchOrderItemService;
import com.block.match.service.ISourceMatchHandleService;
import com.block.merchant.service.IMerchantDataPushInfoService;
import com.block.source.service.ISourceMemberDataInfoService;
import com.block.source.service.ISourcePushResultInfoService;
import net.bytebuddy.dynamic.scaffold.inline.RedefinitionDynamicTypeBuilder;
import org.slf4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;

/**
 * <p>
 * 线索推送结果表 服务实现类
 * </p>
 *
 * @author
 * @since 2023-12-28
 */
@Service
public class SourcePushResultInfoServiceImpl extends ServiceImpl<SourcePushResultInfoMapper, SourcePushResultInfo> implements ISourcePushResultInfoService {

    private static final Logger log = LogFactory.getSourceLog();

    @Autowired
    ISourceMatchHandleService sourceMatchHandleService;
    @Autowired
    ISourceDataCallbackLogService sourceDataCallbackLogService;
    @Resource
    MerchantBaseInfoMapper merchantBaseInfoMapper;
    @Autowired
    ISourceMemberDataInfoService sourceMemberDataInfoService;
    @Resource
    MemberSourceInfoMapper memberSourceInfoMapper;
    @Autowired
    IApplicationInfoService applicationInfoService;
    @Autowired
    IDataMatchOrderItemService dataMatchOrderItemService;
    @Autowired
    ISourceDataCountInfoService sourceDataCountInfoService;
    @Autowired
    NotifyExceptionService notifyExceptionService;
    @Autowired
    ISourceBaseInfoService sourceBaseInfoService;
    @Autowired
    IMerchantThirdBaseInfoService merchantThirdBaseInfoService;
    @Autowired
    ISourcePushResultInfoCommonService sourcePushResultInfoCommonService;
    @Autowired
    MqSourceCountSendService mqSourceCountSendService;
    @Autowired
    ISystemRequestTimeRecordService systemRequestTimeRecordService;
    @Autowired
    IMerchantDataPushInfoService merchantDataPushInfoService;


    /**
     * 撞库完成之后，保存撞库结果
     *
     * @param memberDataInfoTemp
     * @param resultDTO
     * @return
     */
    @Override
    public SourcePushResultInfo savePushResultInfo(SourceMemberDataInfoTemp memberDataInfoTemp, SourceMatchResultDTO resultDTO, SourceBaseInfo sourceBaseInfo) {

        SourcePushResultInfo newEntity = new SourcePushResultInfo();
        newEntity.setDateInfo(LocalDate.now().toString());
        newEntity.setDataId(memberDataInfoTemp.getId());
        newEntity.setChannelCode(memberDataInfoTemp.getChannelCode());
        newEntity.setChannelName(memberDataInfoTemp.getChannelName());
        newEntity.setOutOrderNo(memberDataInfoTemp.getOutOrderNo());
        newEntity.setBaseAmount(sourceBaseInfo.getPriceAmount());// 线索成本
        newEntity.setOrderNo(resultDTO.getOrderNo());
        newEntity.setOrderItemNo(resultDTO.getOrderItemNo());
        newEntity.setInfoId(resultDTO.getInfoId());
        newEntity.setInfoName(resultDTO.getInfoName());
        newEntity.setInfoType(resultDTO.getInfoType());
        newEntity.setTaskId(resultDTO.getTaskId());
        newEntity.setPriceAmount(resultDTO.getPriceAmount());
        newEntity.setRealPriceAmount(resultDTO.getPriceAmount());
        newEntity.setSettleStatus(OrderStatusEnum.INIT.getValue());
        newEntity.setStatus("INIT");
        newEntity.setMessage("待推送");

        // 分润渠道进行处理
        if (ObjectUtil.equals(ProfitSharingEnum.PROFITPRICE.getValue(),sourceBaseInfo.getPriceType()) &&
                resultDTO.getPriceAmount() != null ) {

            // 分润线索，撞库最低价进行处理
            if (sourceBaseInfo.getCheckMinPrice() != null &&
                    resultDTO.getPriceAmount().compareTo(sourceBaseInfo.getCheckMinPrice()) < 0) {
                //更改下游推送状态和返回信息
                MerchantDataPushInfo merchantDataPushInfo = merchantDataPushInfoService.getById(resultDTO.getPushId());
                MerchantDataPushInfo updateEntity = new MerchantDataPushInfo();
                updateEntity.setId(Long.valueOf(resultDTO.getPushId()));
                updateEntity.setCode(merchantDataPushInfo.getCode()+"｜300");
                updateEntity.setMessage(merchantDataPushInfo.getMessage()+"|"+"返回价格过低："+resultDTO.getPriceAmount());
                updateEntity.setStatus(PushStatusEnum.MATCH_FAILED.getValue());
                boolean updateRes = merchantDataPushInfoService.updateById(updateEntity);

                newEntity.setStatus(OrderStatusEnum.PRICE_LOW.getValue());
                newEntity.setMessage(OrderStatusEnum.PRICE_LOW.getName());
            }

//            // 分润线索，进行成交价格处理
//            // 如果实际成交价格> 最高成交价格
//            if (BigDecimalUtil.compare(resultDTO.getPriceAmount(), sourceBaseInfo.getDealMaxPrice()) > 0){
//                BigDecimal bigDecimal = RandomUtil.randomBigDecimal(sourceBaseInfo.getDealMinPrice(), sourceBaseInfo.getDealMaxPrice());
//
//                newEntity.setPriceAmount(bigDecimal);
//                resultDTO.setPriceAmount(bigDecimal);
//            }


            BigDecimal finalPrice=BigDecimal.ZERO;

            if (BigDecimalUtil.compare(resultDTO.getPriceAmount(), sourceBaseInfo.getDealMinPrice()) <= 0) {
                // 实际成交价格小于最低价，直接返回实际价格
                finalPrice = resultDTO.getPriceAmount();
            } else if (BigDecimalUtil.compare(resultDTO.getPriceAmount(), sourceBaseInfo.getDealMaxPrice()) >= 0) {
                // 实际成交价格大于最高价，在最低价和最高价之间取随机数
                finalPrice = RandomUtil.randomBigDecimal(sourceBaseInfo.getDealMinPrice(), sourceBaseInfo.getDealMaxPrice());
            } else {
                // 实际成交价格在最低价和最高价之间，在最低价到实际价格之间取随机数
                finalPrice = RandomUtil.randomBigDecimal(sourceBaseInfo.getDealMinPrice(), resultDTO.getPriceAmount());
            }

            newEntity.setPriceAmount(finalPrice);
            resultDTO.setPriceAmount(finalPrice);

            // 设置成本价格
            // 如果是线索分润，使用分润比例，计算出渠道成本价格
            BigDecimal realBaseAmount = BigDecimalUtil.multiplyReturnDecimal(resultDTO.getPriceAmount(), sourceBaseInfo.getTypeRate());
            newEntity.setBaseAmount(realBaseAmount);
        }

        boolean save = this.save(newEntity);
        if (save) {
            return this.getById(newEntity.getId());
        }
        return null;
    }

    public static void main(String[] args) {
        boolean timeoutFlag = LocalDateTime.now().isAfter(LocalDateUtil.getDateTimeByStr("2024-06-06 12:07:00", LocalDateUtil.TOTAL_DATE_TIME).plusMinutes(30L));
        if (timeoutFlag){
            System.out.println("超时");
        }else{
            System.out.println("不超时");
        }
    }

    /**
     * 获取线索推送订单的信息
     *
     * @param resultNo
     * @return
     */
    @Override
    public ResponseVo getOrderInfo(String resultNo) {

        try {

            SourcePushResultInfo pushResultInfo = this.getById(resultNo);
            if (!StrUtil.equals(pushResultInfo.getStatus(), OrderStatusEnum.WAIT_PUSH.getValue())) {
                return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "订单状态错误");
            }
            // 订单超时
            boolean timeoutFlag = LocalDateTime.now().isAfter(pushResultInfo.getCreateTime().plusMinutes(30L));
            if (timeoutFlag){
                return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION, "订单超时");
            }

            if (ObjectUtil.equals(pushResultInfo.getOpenFlag(), Integer.valueOf(0))) {

                SourceCountDTO sourceCountDTO = new SourceCountDTO(pushResultInfo.getChannelCode(), pushResultInfo.getChannelName());
                sourceCountDTO.setOpenApproveNumber(1);
//                mqSourceCountSendService.sourceDataCountSend(sourceCountDTO);
                sourceDataCountInfoService.saveSourceCountInfo(sourceCountDTO);

                SourcePushResultInfo updateEntity = new SourcePushResultInfo();
                updateEntity.setId(pushResultInfo.getId());
                updateEntity.setOpenFlag(1);
                this.updateById(updateEntity);

                // todo 进行数据结算
                SourceBaseInfo sourceBaseInfo = sourceBaseInfoService.getSourceBaseInfoByCode(pushResultInfo.getChannelCode());
                if (StrUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.APIB_S.getValue())){
                    // 普通回调 走扣量的步骤
                    // 是否进行扣量 判断
                    boolean lessNumberFlag = sourcePushResultInfoCommonService.lessNumberHandle2(pushResultInfo);
                    // 异步执行 统计操作
                    sourcePushResultInfoCommonService.pushResultCount(lessNumberFlag, false, true ,pushResultInfo);
                }
            }

            MerchantBaseInfo merchantBaseInfo = merchantBaseInfoMapper.selectById(pushResultInfo.getInfoId());

            MemberSourceInfo memberSourceInfo = memberSourceInfoMapper.selectById(pushResultInfo.getUid());

            JSONObject returnObject = new JSONObject();
            returnObject.put("resultNo", String.valueOf(pushResultInfo.getId()));
            returnObject.put("orderNo", String.valueOf(pushResultInfo.getOrderNo()));
            returnObject.put("orderItemNo", String.valueOf(pushResultInfo.getOrderItemNo()));

            /**
             * https://apitest.koukoudai.shop/page/protocol/{}/{}
             */
            ApplicationInfo applicationInfo = applicationInfoService.getAppInfoByAppCode(memberSourceInfo.getAppCode());

            // 平台协议地址
            String ownerProtocolUrl = StrUtil.format("{}page/newprotocol/{}/{}.html", applicationInfo.getApiUrl(), pushResultInfo.getOrderNo(), pushResultInfo.getOrderItemNo());

            JSONObject extObject = new JSONObject();
            extObject.put("orderNo", String.valueOf(pushResultInfo.getOrderNo()));
            extObject.put("orderItemNo", String.valueOf(pushResultInfo.getOrderItemNo()));

            // 机构协议地址
            // 如果机构没有协议地址，则使用平台的协议地址
            List<ProtocolInfoEntity> protocolList = PushExtDataFactory.getService(merchantBaseInfo.getFactoryType()).getProtocolUrl(merchantBaseInfo, memberSourceInfo, extObject);
            if (CollUtil.isEmpty(protocolList)) {
                ProtocolInfoEntity infoEntity = new ProtocolInfoEntity();
                infoEntity.setProtocolUrl(ownerProtocolUrl);
                infoEntity.setProtocolName("授权协议");
                protocolList.add(infoEntity);
            }

            returnObject.put("ownerProtocolUrl", ownerProtocolUrl);

            returnObject.put("otherProtocolUrl", protocolList);

            JSONObject dataInfo = new JSONObject();

            if (StrUtil.equals(merchantBaseInfo.getInfoType(), InfoTypeEnum.APIS.getValue())){
                // 查询
                DataMatchOrderItem matchOrderItem = dataMatchOrderItemService.getById(pushResultInfo.getOrderItemNo());
                if (ObjectUtil.isNotEmpty(matchOrderItem)){
                    String pushId = matchOrderItem.getPushId();
                    MerchantThirdBaseInfo thirdBaseInfo = merchantThirdBaseInfoService.selectEntityByOrderNo(pushId);
                    dataInfo.put("compantName", thirdBaseInfo.getCompanyName());
                    dataInfo.put("compantShortName", thirdBaseInfo.getProductName());
                    dataInfo.put("compantTitle", thirdBaseInfo.getBusinessInfo());
                    dataInfo.put("compantSubTitle", thirdBaseInfo.getBusinessInfo());
                    dataInfo.put("compantLogo", thirdBaseInfo.getCompanyLogo());
                    dataInfo.put("maxLoanAmount", thirdBaseInfo.getMaxLoanAmount());
                    dataInfo.put("maxRate", thirdBaseInfo.getMaxLoanRate());
                    dataInfo.put("minRate", thirdBaseInfo.getMinLoanRate());
                }
            }else{
                dataInfo.put("compantName", merchantBaseInfo.getCompanyName());
                dataInfo.put("compantShortName", merchantBaseInfo.getCompanyShortName());
                dataInfo.put("compantTitle", merchantBaseInfo.getCompanyTitle());
                dataInfo.put("compantSubTitle", merchantBaseInfo.getCompanySubTitle());
                dataInfo.put("compantLogo", merchantBaseInfo.getCompanyLogo());
                dataInfo.put("maxLoanAmount", merchantBaseInfo.getMaxLoanAmount());
                dataInfo.put("maxRate", merchantBaseInfo.getMaxRate());
                dataInfo.put("minRate", merchantBaseInfo.getMinRate());
            }

            returnObject.put("dataInfo", dataInfo);

            DataMatchOrderItem matchOrderItem = dataMatchOrderItemService.getById(pushResultInfo.getOrderItemNo());
            JSONObject merchantInfo = new JSONObject();
            merchantInfo.put("infoType", merchantBaseInfo.getInfoType());
            merchantInfo.put("approveUrl", matchOrderItem.getApproveUrl());

            returnObject.put("merchantInfo", merchantInfo);

            return new ResponseVo(AppRspCodeConstant.SUCCESS, returnObject);
        } catch (Exception exception) {
            exception.printStackTrace();
            notifyExceptionService.notifyNoticeInfo("SOURCE_GET_ORDER_INFO", "线索打开", "【resultNo】" + resultNo, exception);
        }
        return new ResponseVo(AppRspCodeConstant.SYS_EXCEPTION);

    }

    /**
     * 推送给商户逻辑
     * 是否推送成功/是否结算/
     * @param pushResultInfo
     */
    @Override
    public SourceRegisterResultDTO handlePushToMerchant(SourcePushResultInfo pushResultInfo) {

        Long time0 = System.currentTimeMillis();
        SourceRegisterResultDTO registerResultDTO = new SourceRegisterResultDTO();
        registerResultDTO.setSuccess(false);
        try {

            // 授权点击统计
            SourceCountDTO sourceCountDTO = new SourceCountDTO(pushResultInfo.getChannelCode(), pushResultInfo.getChannelName());
            sourceCountDTO.setClickApproveNumber(1);
            mqSourceCountSendService.sourceDataCountSend(sourceCountDTO);

            Long time1 = System.currentTimeMillis();

            SourcePushResultInfo updateResult = new SourcePushResultInfo();
            updateResult.setId(pushResultInfo.getId());
            updateResult.setRegisterIp(pushResultInfo.getRegisterIp());

            SourceMatchResultDTO resultDTO = new SourceMatchResultDTO();
            resultDTO.setResultNo(String.valueOf(pushResultInfo.getId()));
            resultDTO.setOrderNo(pushResultInfo.getOrderNo());
            resultDTO.setOrderItemNo(pushResultInfo.getOrderItemNo());

            // 2023/12/28 进行数据推送
            registerResultDTO = sourceMatchHandleService.toPushMerchant(resultDTO);
            log.info("【机构点击推送】推送结束【registerResultDTO】{}", JSON.toJSONString(registerResultDTO));

            Long time2 = System.currentTimeMillis();

            // api 和 crm 进行更新推送结果
            if (!registerResultDTO.isSuccess()) {
                // 推送失败
                updateResult.setStatus(OrderStatusEnum.FAILED.getValue());
                updateResult.setSettleStatus(OrderStatusEnum.FAILED.getValue());
                updateResult.setMessage(registerResultDTO.getMessage());
                this.updateById(updateResult);
                return registerResultDTO;
            }

            Long time3 = System.currentTimeMillis();

            boolean lessNumberFlag = false;
            SourceBaseInfo sourceBaseInfo = sourceBaseInfoService.getSourceBaseInfoByCode(pushResultInfo.getChannelCode());
            if (!StrUtil.equals(sourceBaseInfo.getType(), InfoTypeEnum.APIB_S.getValue())){
                // 非打开结算的都走扣量结算流程
                // 是否进行扣量 判断
                lessNumberFlag = sourcePushResultInfoCommonService.lessNumberHandle2(pushResultInfo);
                // 异步执行 统计操作
                sourcePushResultInfoCommonService.pushResultCount(lessNumberFlag, true, true, pushResultInfo);
            }else{
                // 更新推送结果信息
                updateResult.setId(pushResultInfo.getId());
                updateResult.setStatus("SUCCESS");
                updateResult.setMessage("成功");
                this.updateById(updateResult);
            }

            registerResultDTO.setLessNumberFlag(lessNumberFlag);

            Long time4 = System.currentTimeMillis();
            /**
             * 根据扣量标志 ， 返回是否成功
             */

            if (time4-time0 > 2000){
                RequestTimeDTO timeDTO = new RequestTimeDTO();
                timeDTO.setBizType("MERCHANT_REGISTER_HANDLE");
                timeDTO.setBizName("商户进件流程分步记录");
                timeDTO.setExecTime(String.valueOf(time4- time0));
                timeDTO.setParamInfo(StrUtil.format("【orderNo】{}【channelCode】{}【channelName】{}【infoId】{}【infoName】{}",
                        pushResultInfo.getId(), pushResultInfo.getChannelCode(), pushResultInfo.getChannelName(),pushResultInfo.getInfoId(), pushResultInfo.getInfoName()));
                timeDTO.setResultInfo(JSON.toJSONString(resultDTO));
                timeDTO.setRemarkInfo(StrUtil.format("【time4-time3】{}【time3-time2】{}【time2-time1】{}【time1-time0】{}",
                        time4-time3, time3-time2, time2-time1, time1-time0));
                systemRequestTimeRecordService.saveRequestTime(timeDTO);
            }

        } catch (Exception exception) {
            exception.printStackTrace();
            notifyExceptionService.notifyNoticeInfo("SOURCE_PUSH_TO_EXC", "线索推送异常", "【resultNo】" + pushResultInfo.getId(), exception);
        }
        return registerResultDTO;
    }



}
